package chaoyue.study.juc;

import chaoyue.study.ThreadUtils;

import java.util.concurrent.CompletableFuture;

/**
 * CompletableFuture
 * 基于回调函数的方式的方式可以很方便的实现多任务的组合(类似流程引擎那种方式)
 * 其实里面提供了很多种组合方式，比如是否依赖上一步的结果，是or还是and的关系等等
 */
public class CompletableFutureTest3 {

    public static void main(String[] args) throws Exception {
        //singleChain();
        //doubleChain();
        multiChain();
    }

    /**
     * 单任务链 thenApply
     * f1 -> f2 -> f3
     */
    private static void singleChain() throws Exception {
        CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> {
            ThreadUtils.sleepRandom(3000);
            System.out.println("f1 execute finish");
            return "f1 create";
        });
        CompletableFuture<String> f2 = f1.thenApply((d) -> {
            ThreadUtils.sleepRandom(2000);
            System.out.println("f2 execute finish");
            return d + " f2-add";
        });
        CompletableFuture<Void> f3 = f2.thenAccept((r) -> System.out.println("result: " + r));
        f3.get();
    }

    /**
     * 双任务组合 thenAcceptBoth
     * (f1, f2) -> f3
     */
    private static void doubleChain() throws Exception {
        CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> {
            ThreadUtils.sleep(3000);
            System.out.println("f1 execute finish");
            return "f1 create";
        });
        CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> {
            ThreadUtils.sleep(2000);
            System.out.println("f2 execute finish");
            return "f2 create";
        });
        CompletableFuture<Void> f3 = f1.thenAcceptBoth(f2, (a, b) -> {
            System.out.println("result-f1: " + a + ", result-f2: " + b);
        });
        f3.get();
    }

    /**
     * 多任务组合 CompletableFuture.allOf.get
     */
    private static void multiChain() throws Exception {
        CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> {
            ThreadUtils.sleep(3000);
            System.out.println("f1 execute finish");
            return "f1 create";
        });
        CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> {
            ThreadUtils.sleep(5000);
            System.out.println("f2 execute finish");
            return "f2 create";
        });
        CompletableFuture<String> f3 = CompletableFuture.supplyAsync(() -> {
            ThreadUtils.sleep(1000);
            System.out.println("f3 execute finish");
            return "f3 create";
        });
        CompletableFuture.allOf(f1, f2, f3).get();// 阻塞直到所有任务都完成（可以看作是countdownLatch的替代品）
        System.out.println("all future finish");
        // 然后手动调取每一个的future的get方法获取结果
        System.out.println("result-f1: " + f1.get());
        System.out.println("result-f2: " + f2.get());
        System.out.println("result-f3: " + f3.get());

    }
}
